﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Management;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing;

namespace JWFW.SFL
{
    /// <summary>
    /// 环境操作
    /// </summary>
    public class EnvironmentOP
    {
        /// <summary>
        /// 获取CPU序列号【非硬件，系统设定的】
        /// </summary>
        /// <returns></returns>
        public static string GetCPUID()
        {
            string cpuInfo = "";//cpu序列号
            ManagementClass mc = new ManagementClass("Win32_Processor");
            ManagementObjectCollection moc = mc.GetInstances();
            foreach (ManagementObject mo in moc)
            {
                //var a = mo.Properties.GetEnumerator();
                //while (a.MoveNext())
                //{
                //    cpuInfo += a.Current.Name + ":\t" + a.Current.Value + "\r\n";
                //}
                var v =  mo.Properties["ProcessorId"].Value;
                cpuInfo = (v == null ? "" : v.ToString());
            }
            return cpuInfo;
        }
        /// <summary>
        /// 获取MAC地址
        /// </summary>
        /// <returns></returns>
        public static string GetMacAddress()
        {
            string mac = "";
            ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
            ManagementObjectCollection moc = mc.GetInstances();
            foreach (ManagementObject mo in moc)
            {
                if ((bool)mo["IPEnabled"] == true)
                {
                    mac = mo["MacAddress"].ToString();
                    break;
                }
            }
            return mac;
        }
        /// <summary>
        /// 获取硬盘ID
        /// </summary>
        /// <returns></returns>
        public static string GetDiskID()
        {
            String HDid = "";
            ManagementClass mc = new ManagementClass("Win32_DiskDrive");
            ManagementObjectCollection moc = mc.GetInstances();
            foreach (ManagementObject mo in moc)
            {
                HDid = mo.Properties["signature"].Value.ToString();
            }
            return HDid;
        }
        /// <summary>
        /// 获取IP地址
        /// </summary>
        /// <returns></returns>
        public static string GetIPAddress()
        {
            string st = "";
            ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
            ManagementObjectCollection moc = mc.GetInstances();
            foreach (ManagementObject mo in moc)
            {
                if ((bool)mo["IPEnabled"] == true)
                {
                    //st=mo["IpAddress"].ToString();
                    System.Array ar;
                    ar = (System.Array)(mo.Properties["IpAddress"].Value);
                    st = ar.GetValue(0).ToString();
                    break;
                }
            }
            moc = null;
            mc = null;
            return st;
        }
        /// <summary>
        /// 获取操作系统的登录用户名
        /// </summary>
        /// <returns></returns>
        public static string GetUserName()
        {
            return Environment.UserName;
        }
        /// <summary>
        /// 获取计算机名
        /// </summary>
        /// <returns></returns>
        public static string GetComputerName()
        {
            return System.Environment.MachineName;
        }
        /// <summary>
        /// 获取PC类型
        /// </summary>
        /// <returns></returns>
        public static string GetSystemType()
        {
            string st = "";
            ManagementClass mc = new ManagementClass("Win32_ComputerSystem");
            ManagementObjectCollection moc = mc.GetInstances();
            foreach (ManagementObject mo in moc)
            {

                st = mo["SystemType"].ToString();

            }
            return st;
        }
        /// <summary>
        /// 获取物理内存
        /// </summary>
        /// <returns></returns>
        public static string GetTotalPhysicalMemory()
        {
            string st = "";
            ManagementClass mc = new ManagementClass("Win32_ComputerSystem");
            ManagementObjectCollection moc = mc.GetInstances();
            foreach (ManagementObject mo in moc)
            {

                st = mo["TotalPhysicalMemory"].ToString();

            }
            return st;
        }
        /// <summary>
        /// 获得硬盘信息
        /// </summary>
        public static string GetHDInfo(byte driveIndex)
        {
            switch (Environment.OSVersion.Platform)
            {
                case PlatformID.Win32Windows:
                    return GetHddInfo9x(driveIndex);
                case PlatformID.Win32NT:
                    return GetHddInfoNT(driveIndex);
                case PlatformID.Win32S:
                    throw new NotSupportedException("Win32s is not supported.");
                case PlatformID.WinCE:
                    throw new NotSupportedException("WinCE is not supported.");
                default:
                    throw new NotSupportedException("Unknown Platform.");
            }
        }

        #region 获取硬盘信息的实现

        #region 结构

        /*
        [Serializable]
        internal struct HardDiskInfo
        {
            /// <summary>
            /// 型号
            /// </summary>
            public string ModuleNumber;
            /// <summary>
            /// 固件版本
            /// </summary>
            public string Firmware;
            /// <summary>
            /// 序列号
            /// </summary>
            public string SerialNumber;
            /// <summary>
            /// 容量，以M为单位
            /// </summary>
            public uint Capacity;
        }
         * 
         * */
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct GetVersionOutParams
        {
            public byte bVersion;
            public byte bRevision;
            public byte bReserved;
            public byte bIDEDeviceMap;
            public uint fCapabilities;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public uint[] dwReserved; // For future use.
        }
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct IdeRegs
        {
            public byte bFeaturesReg;
            public byte bSectorCountReg;
            public byte bSectorNumberReg;
            public byte bCylLowReg;
            public byte bCylHighReg;
            public byte bDriveHeadReg;
            public byte bCommandReg;
            public byte bReserved;
        }
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct SendCmdInParams
        {
            public uint cBufferSize;
            public IdeRegs irDriveRegs;
            public byte bDriveNumber;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
            public byte[] bReserved;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public uint[] dwReserved;
            public byte bBuffer;
        }
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct DriverStatus
        {
            public byte bDriverError;
            public byte bIDEStatus;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
            public byte[] bReserved;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
            public uint[] dwReserved;
        }
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct SendCmdOutParams
        {
            public uint cBufferSize;
            public DriverStatus DriverStatus;
            public IdSector bBuffer;
        }
        [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 512)]
        internal struct IdSector
        {
            public ushort wGenConfig;
            public ushort wNumCyls;
            public ushort wReserved;
            public ushort wNumHeads;
            public ushort wBytesPerTrack;
            public ushort wBytesPerSector;
            public ushort wSectorsPerTrack;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
            public ushort[] wVendorUnique;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
            public byte[] sSerialNumber;
            public ushort wBufferType;
            public ushort wBufferSize;
            public ushort wECCSize;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
            public byte[] sFirmwareRev;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
            public byte[] sModelNumber;
            public ushort wMoreVendorUnique;
            public ushort wDoubleWordIO;
            public ushort wCapabilities;
            public ushort wReserved1;
            public ushort wPIOTiming;
            public ushort wDMATiming;
            public ushort wBS;
            public ushort wNumCurrentCyls;
            public ushort wNumCurrentHeads;
            public ushort wNumCurrentSectorsPerTrack;
            public uint ulCurrentSectorCapacity;
            public ushort wMultSectorStuff;
            public uint ulTotalAddressableSectors;
            public ushort wSingleWordDMA;
            public ushort wMultiWordDMA;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
            public byte[] bReserved;
        }

        #endregion

        #region API

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern int CloseHandle(IntPtr hObject);

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr CreateFile(
         string lpFileName,
         uint dwDesiredAccess,
         uint dwShareMode,
         IntPtr lpSecurityAttributes,
         uint dwCreationDisposition,
         uint dwFlagsAndAttributes,
         IntPtr hTemplateFile);

        [DllImport("kernel32.dll")]
        static extern int DeviceIoControl(
         IntPtr hDevice,
         uint dwIoControlCode,
         IntPtr lpInBuffer,
         uint nInBufferSize,
         ref GetVersionOutParams lpOutBuffer,
         uint nOutBufferSize,
         ref uint lpBytesReturned,
         [Out] IntPtr lpOverlapped);

        [DllImport("kernel32.dll")]
        static extern int DeviceIoControl(
         IntPtr hDevice,
         uint dwIoControlCode,
         ref SendCmdInParams lpInBuffer,
         uint nInBufferSize,
         ref SendCmdOutParams lpOutBuffer,
         uint nOutBufferSize,
         ref uint lpBytesReturned,
         [Out] IntPtr lpOverlapped);


        const uint DFP_GET_VERSION = 0x00074080;
        const uint DFP_SEND_DRIVE_COMMAND = 0x0007c084;
        const uint DFP_RECEIVE_DRIVE_DATA = 0x0007c088;


        const uint GENERIC_READ = 0x80000000;
        const uint GENERIC_WRITE = 0x40000000;
        const uint FILE_SHARE_READ = 0x00000001;
        const uint FILE_SHARE_WRITE = 0x00000002;
        const uint CREATE_NEW = 1;
        const uint OPEN_EXISTING = 3;


        #endregion

        /// <summary>
        /// 获取9X架构的硬盘信息
        /// </summary>
        /// <param name="driveIndex"></param>
        /// <returns></returns>
        private static string GetHddInfo9x(byte driveIndex)
        {
            GetVersionOutParams vers = new GetVersionOutParams();
            SendCmdInParams inParam = new SendCmdInParams();
            SendCmdOutParams outParam = new SendCmdOutParams();
            uint bytesReturned = 0;


            IntPtr hDevice = CreateFile(
             @"\\.\Smartvsd",
             0,
             0,
             IntPtr.Zero,
             CREATE_NEW,
             0,
             IntPtr.Zero);
            if (hDevice == IntPtr.Zero)
            {
                throw new Exception("Open smartvsd.vxd failed.");
            }
            if (0 == DeviceIoControl(
             hDevice,
             DFP_GET_VERSION,
             IntPtr.Zero,
             0,
             ref vers,
             (uint)Marshal.SizeOf(vers),
             ref bytesReturned,
             IntPtr.Zero))
            {
                CloseHandle(hDevice);
                throw new Exception("DeviceIoControl failed:DFP_GET_VERSION");
            }
            // If IDE identify command not supported, fails
            if (0 == (vers.fCapabilities & 1))
            {
                CloseHandle(hDevice);
                throw new Exception("Error: IDE identify command not supported.");
            }
            if (0 != (driveIndex & 1))
            {
                inParam.irDriveRegs.bDriveHeadReg = 0xb0;
            }
            else
            {
                inParam.irDriveRegs.bDriveHeadReg = 0xa0;
            }
            if (0 != (vers.fCapabilities & (16 >> driveIndex)))
            {
                // We don''t detect a ATAPI device.
                CloseHandle(hDevice);
                throw new Exception(string.Format("Drive {0} is a ATAPI device, we don''t detect it", driveIndex + 1));
            }
            else
            {
                inParam.irDriveRegs.bCommandReg = 0xec;
            }
            inParam.bDriveNumber = driveIndex;
            inParam.irDriveRegs.bSectorCountReg = 1;
            inParam.irDriveRegs.bSectorNumberReg = 1;
            inParam.cBufferSize = 512;
            if (0 == DeviceIoControl(
             hDevice,
             DFP_RECEIVE_DRIVE_DATA,
             ref inParam,
             (uint)Marshal.SizeOf(inParam),
             ref outParam,
             (uint)Marshal.SizeOf(outParam),
             ref bytesReturned,
             IntPtr.Zero))
            {
                CloseHandle(hDevice);
                throw new Exception("DeviceIoControl failed: DFP_RECEIVE_DRIVE_DATA");
            }
            CloseHandle(hDevice);


            return GetHardDiskInfo(outParam.bBuffer);
        }
        /// <summary>
        /// 获取NT架构的硬盘信息
        /// </summary>
        /// <param name="driveIndex"></param>
        /// <returns></returns>
        private static string GetHddInfoNT(byte driveIndex)
        {
            GetVersionOutParams vers = new GetVersionOutParams();
            SendCmdInParams inParam = new SendCmdInParams();
            SendCmdOutParams outParam = new SendCmdOutParams();
            uint bytesReturned = 0;


            // We start in NT/Win2000
            IntPtr hDevice = CreateFile(
             string.Format(@"\\.\PhysicalDrive{0}", driveIndex),
             GENERIC_READ | GENERIC_WRITE,
             FILE_SHARE_READ | FILE_SHARE_WRITE,
             IntPtr.Zero,
             OPEN_EXISTING,
             0,
             IntPtr.Zero);
            if (hDevice == IntPtr.Zero)
            {
                throw new Exception("CreateFile faild.");
            }
            if (0 == DeviceIoControl(
             hDevice,
             DFP_GET_VERSION,
             IntPtr.Zero,
             0,
             ref vers,
             (uint)Marshal.SizeOf(vers),
             ref bytesReturned,
             IntPtr.Zero))
            {
                CloseHandle(hDevice);
                throw new Exception(string.Format("Drive {0} may not exists.", driveIndex + 1));
            }
            // If IDE identify command not supported, fails
            if (0 == (vers.fCapabilities & 1))
            {
                CloseHandle(hDevice);
                throw new Exception("Error: IDE identify command not supported.");
            }
            // Identify the IDE drives
            if (0 != (driveIndex & 1))
            {
                inParam.irDriveRegs.bDriveHeadReg = 0xb0;
            }
            else
            {
                inParam.irDriveRegs.bDriveHeadReg = 0xa0;
            }
            if (0 != (vers.fCapabilities & (16 >> driveIndex)))
            {
                CloseHandle(hDevice);
                throw new Exception(string.Format("Drive {0} is a ATAPI device, we don''t detect it.", driveIndex + 1));
            }
            else
            {
                inParam.irDriveRegs.bCommandReg = 0xec;
            }
            inParam.bDriveNumber = driveIndex;
            inParam.irDriveRegs.bSectorCountReg = 1;
            inParam.irDriveRegs.bSectorNumberReg = 1;
            inParam.cBufferSize = 512;


            if (0 == DeviceIoControl(
             hDevice,
             DFP_RECEIVE_DRIVE_DATA,
             ref inParam,
             (uint)Marshal.SizeOf(inParam),
             ref outParam,
             (uint)Marshal.SizeOf(outParam),
             ref bytesReturned,
             IntPtr.Zero))
            {
                CloseHandle(hDevice);
                throw new Exception("DeviceIoControl failed: DFP_RECEIVE_DRIVE_DATA");
            }
            CloseHandle(hDevice);


            return GetHardDiskInfo(outParam.bBuffer);
        }
        /// <summary>
        /// 获取硬盘信息的细节
        /// </summary>
        /// <param name="phdinfo"></param>
        /// <returns></returns>
        private static string GetHardDiskInfo(IdSector phdinfo)
        {
            //HardDiskInfo hddInfo = new HardDiskInfo();
            ChangeByteOrder(phdinfo.sModelNumber);
            //hddInfo.ModuleNumber = Encoding.ASCII.GetString(phdinfo.sModelNumber).Trim();

            ChangeByteOrder(phdinfo.sFirmwareRev);
            //hddInfo.Firmware = Encoding.ASCII.GetString(phdinfo.sFirmwareRev).Trim();

            ChangeByteOrder(phdinfo.sSerialNumber);
            string res = Encoding.ASCII.GetString(phdinfo.sSerialNumber).Trim();
            //hddInfo.SerialNumber = res;

            //hddInfo.Capacity = phdinfo.ulTotalAddressableSectors / 2 / 1024;
            //改为只返回硬盘序列号的字符串，便于混淆
            return res;
        }
        /// <summary>
        /// 将byte数组中保存的信息转换成字符串
        /// </summary>
        /// <param name="charArray"></param>
        private static void ChangeByteOrder(byte[] charArray)
        {
            byte temp;
            for (int i = 0; i < charArray.Length; i += 2)
            {
                temp = charArray[i];
                charArray[i] = charArray[i + 1];
                charArray[i + 1] = temp;
            }
        }

        #endregion

        #region 系统ImageList

        #region 常量
        private static uint SHGFI_ICON = 0x100;
        private static uint SHGFI_DISPLAYNAME = 0x200;
        private static uint SHGFI_TYPENAME = 0x400;
        private static uint SHGFI_ATTRIBUTES = 0x800;
        private static uint SHGFI_ICONLOCATION = 0x1000;
        private static uint SHGFI_EXETYPE = 0x2000;
        private static uint SHGFI_SYSICONINDEX = 0x4000;
        private static uint SHGFI_LINKOVERLAY = 0x8000;
        private static uint SHGFI_SELECTED = 0x10000;
        private static uint SHGFI_LARGEICON = 0x0;
        private static uint SHGFI_SMALLICON = 0x1;
        private static uint SHGFI_OPENICON = 0x2;
        private static uint SHGFI_SHELLICONSIZE = 0x4;
        private static uint SHGFI_PIDL = 0x8;
        private static uint SHGFI_USEFILEATTRIBUTES = 0x10;

        private static uint FILE_ATTRIBUTE_NORMAL = 0x80;
        private static uint LVM_FIRST = 0x1000;
        private static uint LVM_SETIMAGELIST = LVM_FIRST + 3;
        private static uint LVSIL_NORMAL = 0;
        private static uint LVSIL_SMALL = 1;

        #endregion

        #region 结构
        /// <summary>
        /// 存储文件信息的结构
        /// </summary>
        private struct SHFILEINFO
        {
            public IntPtr hIcon;
            public int iIcon;
            public int dwAttributes;
            public string szDisplayName;
            public string szTypeName;
        }
        #endregion

        #region API

        [DllImport("Shell32.dll")]
        private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, int cbfileInfo, uint uFlags);
        [DllImport("User32.DLL")]
        private static extern int SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        #endregion

        /// <summary>
        /// 将系统ImageList附加到指定的控件
        /// </summary>
        /// <param name="ctrl">控件</param>
        /// <param name="largeIcon">是否获取大图标</param>
        public static void AttachSystemImageListToControl(Control ctrl, bool largeIcon)
        {
            IntPtr vImageList = GetSystemImageList(largeIcon);
            SendMessage(ctrl.Handle, LVM_SETIMAGELIST, largeIcon ? (IntPtr)LVSIL_NORMAL : (IntPtr)LVSIL_SMALL,
                vImageList);
        }
        /// <summary>
        /// 获取指定文件对应的系统图标索引
        /// </summary>
        /// <param name="fileName">文件全名</param>
        /// <returns>文件对应的系统图标索引</returns>
        public static int FileIconIndex(string fileName)
        {
            SHFILEINFO vFileInfo = new SHFILEINFO();
            SHGetFileInfo(fileName, 0, ref vFileInfo,
                Marshal.SizeOf(vFileInfo), SHGFI_SYSICONINDEX);
            return vFileInfo.iIcon;
        }
        /// <summary>
        /// 获取指定文件对应的系统图标
        /// </summary>
        /// <param name="fileName">文件全名</param>
        /// <param name="largeIcon">是否获取大图标</param>
        /// <returns>文件对应的系统图标</returns>
        public static Icon FileIcon(string fileName,bool largeIcon)
        {
            SHFILEINFO vFileInfo = new SHFILEINFO();
            SHGetFileInfo(fileName, 0, ref vFileInfo,
                Marshal.SizeOf(vFileInfo), SHGFI_SHELLICONSIZE | SHGFI_ICON | (largeIcon ? SHGFI_LARGEICON : SHGFI_SMALLICON));
            try
            {
                Icon res = Icon.FromHandle(vFileInfo.hIcon);
                return res;
            }
            catch { return null; }
        }
        /// <summary>
        /// 获取系统ImageList的指针
        /// </summary>
        /// <param name="largeIcon">是否获取大图标</param>
        /// <returns></returns>
        public static IntPtr GetSystemImageList(bool largeIcon)
        {
            SHFILEINFO vFileInfo = new SHFILEINFO();
            IntPtr res = SHGetFileInfo("", 0, ref vFileInfo,
                Marshal.SizeOf(vFileInfo),
                SHGFI_SHELLICONSIZE | SHGFI_SYSICONINDEX | (largeIcon ? SHGFI_LARGEICON : SHGFI_SMALLICON));
            return res;
        }

        #endregion

        protected void Test()
        {
            Console.WriteLine(GetCPUID());
            Console.WriteLine(GetMacAddress());
            Console.WriteLine(GetDiskID());
            Console.WriteLine(GetIPAddress());
            Console.WriteLine(GetUserName());
            Console.WriteLine(GetComputerName());
            Console.WriteLine(GetSystemType());
            Console.WriteLine(GetTotalPhysicalMemory());
            Console.WriteLine(GetHDInfo(0));
        }
    }
}
